package game.map;

import game.map.mapEvents.MapEvent;
import game.map.mapEvents.TriggerBattleEvent;
import game.mechanics.GameTurn;
import game.units.Monster;
import game.units.Unit;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import processing.core.PConstants;

import communication.server.MasterInteractionManager;

public class MapInteractionServer extends MapInteraction {

	private MapUnit drag;

	private boolean paused = false;
	private boolean dragin = false;
	private boolean shift; // for attack
	private Unit selectedUnit;
	
	private GameTurn gameTurn;
	
	private int mouX, mouY;
	private boolean pressed = false;

	private MasterInteractionManager master = null;
	
	private MapUnit movingUnit = null;
	
	public enum Tools { REMOVE_ITEM };

	public MapInteractionServer(TiledMapInGame tm, WsApplet app) {
		super(tm, app);
		initialize(tm, app);
	}

	@Override
	protected void initialize(TiledMapInGame tm, WsApplet app) {
		this.master = app.getMaster();
	}
	
	@Override
	protected void translate() {
		app.translate(centerX, centerY);
		if (app.mousePressed && !ctrl)
			app.translate(app.mouseX - mouX, app.mouseY - mouY);
	}

	public void pause() {
		//TODO
		this.paused = !paused;
	}

	public void setTurnOrder() {

		List<MapUnit> units = tm.getActiveUnits();

		for (MapUnit mu : units)
			mu.rollInitiative();
		Collections.sort(units);
	}
	
	public void setMovingUnit(long id) {
		for (MapUnit u : tm.getUnits())
			if (u.getId() == id) {
				movingUnit = u;
				gameTurn = new GameTurn(movingUnit);
			}
	}

	public ArrayList<MapUnit> triggerBattle(int x, int y) {

		MapEvent ev = tm.getEvent(x, y);
		if (ev == null || !(ev instanceof TriggerBattleEvent)) // error
			return null;
		TriggerBattleEvent tbev = (TriggerBattleEvent) ev;
		
		List<MapUnit> units = tm.getUnits();
		ArrayList<MapUnit> monsters = new ArrayList<MapUnit>();
		for (MapUnit unit : units) {
			if (unit.getUnit() instanceof Monster)
				monsters.add(unit);
		}
		ArrayList<MapUnit> triggeredUnits = new ArrayList<MapUnit>(); 
		for (MapUnit unit : monsters)
			if (tbev.inArea(unit.getPlannedX(), unit.getPlannedY()))
				triggeredUnits.add(unit);
				
//		tm.setActiveUnits(triggeredUnits);
//		setTurnOrder(); // needs testing
		return triggeredUnits;
	}

	@Override
	public void mousePressed() {
		
		if (tool != null) {
			if (tool == Tools.REMOVE_ITEM) {
				System.out.println("remove item!");
				MapItem mi = tm.getItem((app.mouseX - centerX) / tm.getSide(), 
						(app.mouseY - centerY) / tm.getSide());
				if (mi != null)
					tm.getItens().remove(mi);
			}
			tool = null;
		}
		
		if (ctrl) {
			drag();
			if (drag != null)
				dragin = true;
			return;
		}
		
		super.mousePressed();

		if (!pressed) {
			pressed = true;
			mouX = app.mouseX;
			mouY = app.mouseY;
		}
		
	}

	@Override
	public void mouseDragged() {
	}

	@Override
	public void mouseReleased() {

		if (dragin) {
			drop();
			return;
		}
		
		if (!ctrl) {
			centerX -= mouX - app.mouseX;
			centerY -= mouY - app.mouseY;
		}

		pressed = false;
		
	}
	
	public void keyPressed(char key) {
		if (key == PConstants.CODED)
			switch (app.keyCode) {
				case PConstants.LEFT:
				case PConstants.RIGHT:
				case PConstants.UP:
				case PConstants.DOWN:
					if (isYourTurnKey())
						move(app.keyCode);
					break;
				case PConstants.CONTROL:
					ctrl = true;
					break;
				case PConstants.SHIFT:
					shift = true;
					break;
			}
		else
			switch (key) {
				case 'z':
					if (isYourTurnKey()) {
						//TODO:
						gameTurn.undoMoves();
						movingUnit.undoMoves();
						master.informSetPosition(movingUnit.getId(), movingUnit.getPlannedX(), movingUnit.getPlannedY());
					}
					break;
			}

	}

	public void keyReleased() {
		if (app.key == PConstants.CODED) {
			if (app.keyCode == PConstants.CONTROL)
				ctrl = false;
			else if (app.keyCode == PConstants.SHIFT)
				shift = false;
		}
	}
	
	public void move(int direction) {

		movingUnit.face(direction);

		if (ctrl)
			return;

		// TODO: see in 'turn actions' if still can move
//		if (!gameTurn.action(GameTurn.TurnAction.MOVE))
//			return;

		int x = movingUnit.getPlannedX();
		int y = movingUnit.getPlannedY();

		switch (direction) {
			case PConstants.LEFT:
				if (tm.noWallToTheLeft(x, y)) {
					tm.entityCollision(x - 1, y, movingUnit);
				}
				break;
			case PConstants.RIGHT:
				if (tm.noWallToTheRight(x, y)) {
					tm.entityCollision(x + 1, y, movingUnit);
				}
				break;
			case PConstants.UP:
				if (tm.noWallAbove(x, y)) {
					tm.entityCollision(x, y - 1, movingUnit);
				}
				break;
			case PConstants.DOWN:
				if (tm.noWallBelow(x, y)) {
					tm.entityCollision(x, y + 1, movingUnit);
				}
				break;
		}

//		MapEvent event = tm.getEvent(movingUnit.getPlannedX(), movingUnit.getPlannedY());
//		if (event != null)
//			handleEvent(event);
		master.informSetPosition(movingUnit.getId(), movingUnit.getPlannedX(), movingUnit.getPlannedY());

	}

	private void drag() {
		drag = tm.getUnit(app.mouseX - centerX, app.mouseY - centerY);
		System.out.println(drag);
	}

	private void drop() {
		int side = tm.getSide();
		if (!dragin)
			return;

		dragin = false;
		master.informPosition(drag.getId(), (app.mouseX - centerX) / side,
				(app.mouseY - centerY) / side);
		drag.canStayHere(true);
		drag = null;
	}

	@Override
	public int[][] setVisibility() {
		return null; // I see all
	}

	@Override
	protected boolean canOpenDoor(int[] door) {
		return true; // I open all
	}
	
	@Override
	public void draw() {
		super.draw();
		
		// draw events indicators
		for (MapEvent ev : tm.getEvents()) {
			ev.drawIndicator(app, tm.getSide());
		}
		
		MapUnit u = tm.getUnit(app.mouseX - centerX, app.mouseY - centerY);
		if (u != null)
			u.drawGlow(app, tm.getSide());

		if (drag != null)
			drag.drawGhost(app, tm.getSide(), centerX, centerY);
	}

	public void dragAndDungeon() {
		dragin = true;
		drag();
	}

	public Unit getSelectedUnit() {
		return selectedUnit;
	}

	public void setSelectedUnit(Unit selectedUnit) {
		this.selectedUnit = selectedUnit;
	}
	
	@Override
	public boolean isYourTurnKey() {
		boolean turn = false;
		for (int i = 0; i < master.getPlayableUnits().size(); i++) {
			if(!turn) {
				turn = master.getCurrentPlayer() == master.getPlayableUnits().get(i).getId();
			}
		}
		return turn;
	}
	
	@Override
	public boolean isYourTurnMouse() {
		return true;
	}
	
	public void commitMove() {
		movingUnit.commitMove();
	}

	private Tools tool;
	public void setTool(Tools tool) {
		this.tool = tool;
		System.out.println("ready to remove!");
	}

}
